/* ============================================================
 * Part of 'Autostop' project
 * Under GPL license - http://www.gnu.org/licenses/gpl.html
 * (c) 2006 - Autostop team
 */

///\file camera.c implementation of the camera driver-to-userspace library

#include <fcntl.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <sys/time.h>
#include <stdio.h>

#include "registers.h"
#include "camera.h"

// =================
// consts

/// default device file name
#define TOOLS_DEFAULT_DEVICE	"/autostop/dev/camera"

// =================
// globals

const char* error_message	=	"";		// error message
int device = -1;						// device handler


// ========================================================
int camera_init(void)
{
	// try to open device
	device = open( TOOLS_DEFAULT_DEVICE, O_RDONLY );
	if ( device < 0 ) {
		error_message = "could not open device file " TOOLS_DEFAULT_DEVICE;
		return CAMERA_ERROR;
	}
	
	// set camera in raw reading mode
	write_register( device, CWR_CR, CCR_ENYX );
	
	return CAMERA_OK;
}

// ========================================================
int camera_image_width(void)
{
	return 640;
}

// ========================================================
int camera_image_height(void)
{
	return 480;
}

// ========================================================
int camera_get_image( uint8_t* pbuffer, size_t bufsize, uint64_t* ptimestamp )
{
	int waiting = 0;	// waiting [us]
	int i = 0 ; // index
	struct timeval start, end;
	uint64_t startms, endms;
	
	// check device
	if ( device < 0 ) {
		error_message = "not initilaized";
		return CAMERA_ERROR;
	}
	
	// wait for 'ready' bit
	while( ! ( read_register( device, CRD_STAT1 ) & ( CSTAT1_JNBY | CSTAT1_JNBY2 ) ) )
	{
		// wait a bit
		usleep( 10 );
		// inc waiting counter
		waiting += 10;
		// check if this is sane time
		if (waiting > 10000 )
		{
			error_message = "timeout waiting for image data";
			return CAMERA_ERROR;
		}
	}
	
	// TODO debug
	printf("witing for image: %d us\n", waiting );
	
	// get start time
	gettimeofday( & start, NULL );
	startms = (uint64_t)start.tv_sec * 1000 + start.tv_usec / 1000;
	
	// copy time to user supplied buffer
	if ( ptimestamp )
	{
		*ptimestamp = startms;
	}
	
	// set 'read' bit
	write_register( device, CWR_CR, CCR_ENYX | CCR_CZYTYX );
	
	// read header
	read_register( device, CRD_FF ); // ignore for now
	read_register( device, CRD_FF );
	
	// read
	// cool new modern and hyperfast
	read_multi_hibytes( device, CRD_FF, pbuffer, bufsize );
	
	
	// clear 'read' bit
	write_register( device, CWR_CR, CCR_ENYX );
	
	// get end time (DEBUG)
	gettimeofday( & end, NULL );
	endms = (uint64_t)end.tv_sec * 1000 + end.tv_usec / 1000;
	
	// display total time (DEBUG)
	printf("reading frame: %d ms\n", (int)(endms-startms) );
	
	return CAMERA_OK;
}

// ========================================================
sequence_t camera_open_sequence(void)
{
	return SEQUENCE_INVALID;
}

// ========================================================
int camera_read_sequence( sequence_t sequence, uint8_t* pbuffer, size_t bufsize )
{
	return CAMERA_ERROR;
}

// ========================================================
void camera_close_sequence( sequence_t sequence )
{
}

// ========================================================
const char* camera_error_message()
{
	return error_message;
}

// eof

